Şablon dizi ve koşullu tipler gibi gelişmiş TypeScript özellikleriyle daha etkileyici kodlar yazın. Karmaşık senaryolar için tip manipülasyonunda ustalaşın.
TypeScript İleri Seviye Tipler: Şablon Dizi ve Koşullu Tiplerde Uzmanlaşma
TypeScript'in gücü, sahip olduğu güçlü tip sisteminden gelir. string, number ve boolean gibi temel tipler birçok senaryo için yeterli olsa da, şablon dizi tipleri ve koşullu tipler gibi gelişmiş özellikler, ifade gücü ve tip güvenliğinde yeni bir seviyenin kapılarını aralar. Bu kılavuz, bu ileri seviye tiplere kapsamlı bir genel bakış sunarak yeteneklerini keşfeder ve pratik uygulamalarını gösterir.
Şablon Dizi Tiplerini Anlama
Şablon dizi tipleri, JavaScript'in şablon dizileri üzerine inşa edilmiştir ve dize interpolasyonuna dayalı tipler tanımlamanıza olanak tanır. Bu, belirli dize desenlerini temsil eden tipler oluşturmayı mümkün kılarak kodunuzu daha sağlam ve öngörülebilir hale getirir.
Temel Sözdizimi ve Kullanım
Şablon dizi tipleri, JavaScript şablon dizilerine benzer şekilde, tip tanımını sarmak için ters tırnak (`) kullanır. Ters tırnaklar içinde, ${} sözdizimini kullanarak diğer tipleri interpole edebilirsiniz. Büyü burada gerçekleşir – esasen, derleme zamanında interpolasyon içindeki tiplere dayalı olarak oluşturulan bir dize olan bir tip yaratırsınız.
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIEndpoint = `/api/${string}`;
// Örnek Kullanım
const getEndpoint: APIEndpoint = "/api/users"; // Geçerli
const postEndpoint: APIEndpoint = "/api/products/123"; // Geçerli
const invalidEndpoint: APIEndpoint = "/admin/settings"; // TypeScript burada bir hata göstermeyecektir çünkü `string` herhangi bir şey olabilir
Bu örnekte, APIEndpoint, /api/ ile başlayan herhangi bir dizeyi temsil eden bir tiptir. Bu temel örnek faydalı olsa da, şablon dizi tiplerinin gerçek gücü, daha spesifik tip kısıtlamalarıyla birleştirildiğinde ortaya çıkar.
Union Tiplerle Birleştirme
Şablon dizi tipleri, union tiplerle kullanıldığında gerçekten parlar. Bu, belirli bir dize kombinasyonları kümesini temsil eden tipler oluşturmanıza olanak tanır.
type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE";
type APIPath = "users" | "products" | "orders";
type APIEndpoint = `/${APIPath}/${HTTPMethod}`;
// Geçerli API Uç Noktaları
const getUsers: APIEndpoint = "/users/GET";
const postProducts: APIEndpoint = "/products/POST";
// Geçersiz API Uç Noktaları (TypeScript hatalarına neden olacaktır)
// const invalidEndpoint: APIEndpoint = "/users/PATCH"; // Hata: "/users/PATCH" tipi "/users/GET" | "/users/POST" | "/users/PUT" | "/users/DELETE" | "/products/GET" | "/products/POST" | ... 3 tane daha ... | "/orders/DELETE" tipine atanamaz.
Şimdi, APIEndpoint, yalnızca API yolları ve HTTP metotlarının belirli kombinasyonlarına izin veren daha kısıtlayıcı bir tiptir. TypeScript, geçersiz kombinasyonları kullanma girişimlerini işaretleyerek tip güvenliğini artırır.
Şablon Dizi Tipleri ile Dize Manipülasyonu
TypeScript, şablon dizi tipleriyle sorunsuz bir şekilde çalışan yerleşik dize manipülasyon tipleri sunar. Bu tipler, dizeleri derleme zamanında dönüştürmenize olanak tanır.
- Uppercase: Bir dizeyi büyük harfe çevirir.
- Lowercase: Bir dizeyi küçük harfe çevirir.
- Capitalize: Bir dizenin ilk harfini büyük harfe çevirir.
- Uncapitalize: Bir dizenin ilk harfini küçük harfe çevirir.
type Greeting = "hello world";
type UppercaseGreeting = Uppercase; // "HELLO WORLD"
type LowercaseGreeting = Lowercase; // "hello world"
type CapitalizedGreeting = Capitalize; // "Hello world"
type UncapitalizedGreeting = Uncapitalize; // "hello world"
Bu dize manipülasyon tipleri, isimlendirme kurallarına dayalı olarak otomatik olarak tipler oluşturmak için özellikle kullanışlıdır. Örneğin, olay adlarından eylem tipleri türetebilir veya tam tersini yapabilirsiniz.
Şablon Dizi Tiplerinin Pratik Uygulamaları
- API Endpoint Definition: Yukarıda gösterildiği gibi, API uç noktalarını kesin tip kısıtlamalarıyla tanımlama.
- Event Handling: Belirli ön ekler ve son eklerle olay adları için tipler oluşturma.
- CSS Class Generation: Bileşen adlarına ve durumlarına göre CSS sınıf adları oluşturma.
- Database Query Building: Veritabanı sorguları oluştururken tip güvenliğini sağlama.
Uluslararası Örnek: Para Birimi Biçimlendirme
Birden fazla para birimini destekleyen bir finansal uygulama geliştirdiğinizi hayal edin. Doğru para birimi biçimlendirmesini zorunlu kılmak için şablon dizi tiplerini kullanabilirsiniz.
type CurrencyCode = "USD" | "EUR" | "GBP" | "JPY";
type CurrencyFormat = `${number} ${T}`;
const priceUSD: CurrencyFormat<"USD"> = "100 USD"; // Geçerli
const priceEUR: CurrencyFormat<"EUR"> = "50 EUR"; // Geçerli
// const priceInvalid: CurrencyFormat<"USD"> = "100 EUR"; // Hata: 'string' tipi '`${number} USD`' tipine atanamaz.
function formatCurrency(amount: number, currency: T): CurrencyFormat {
return `${amount} ${currency}`;
}
const formattedUSD = formatCurrency(250, "USD"); // Tip: "250 USD"
const formattedEUR = formatCurrency(100, "EUR"); // Tip: "100 EUR"
Bu örnek, para birimi değerlerinin her zaman doğru para birimi koduyla biçimlendirilmesini sağlayarak olası hataları önler.
Koşullu Tipleri Derinlemesine İnceleme
Koşullu tipler, TypeScript'in tip sistemine dallanma mantığı ekleyerek diğer tiplere bağlı tipler tanımlamanıza olanak tanır. Bu özellik, son derece esnek ve yeniden kullanılabilir tip tanımları oluşturmak için inanılmaz derecede güçlüdür.
Temel Sözdizimi ve Kullanım
Koşullu tipler, tip koşullarını tanımlamak için infer anahtar kelimesini ve üçlü operatörü (koşul ? doğruTip : yanlışTip) kullanır.
type IsString = T extends string ? true : false;
type StringCheck = IsString; // type StringCheck = true
type NumberCheck = IsString; // type NumberCheck = false
Bu örnekte, IsString, T'nin string'e atanabilir olup olmadığını kontrol eden koşullu bir tiptir. Eğer öyleyse, tip true olarak çözümlenir; aksi takdirde false olarak çözümlenir.
infer Anahtar Kelimesi
infer anahtar kelimesi, bir tipten başka bir tip çıkarmanıza olanak tanır. Bu, fonksiyon tipleri veya dizi tipleri gibi karmaşık tiplerle çalışırken özellikle kullanışlıdır.
type ReturnType any> = T extends (...args: any) => infer R ? R : any;
function add(a: number, b: number): number {
return a + b;
}
type AddReturnType = ReturnType; // type AddReturnType = number
Bu örnekte, ReturnType bir T fonksiyon tipinin geri dönüş tipini çıkarır. Koşullu tipin infer R kısmı, geri dönüş tipini çıkarır ve onu R tip değişkenine atar. Eğer T bir fonksiyon tipi değilse, tip any olarak çözümlenir.
Dağıtıcı Koşullu Tipler
Koşullu tipler, kontrol edilen tip çıplak bir tip parametresi olduğunda dağıtıcı hale gelir. Bu, koşullu tipin union tipinin her bir üyesine ayrı ayrı uygulandığı anlamına gelir.
type ToArray = T extends any ? T[] : never;
type NumberOrStringArray = ToArray; // type NumberOrStringArray = string[] | number[]
Bu örnekte, ToArray bir T tipini bir dizi tipine dönüştürür. T çıplak bir tip parametresi olduğu için (başka bir tip içine sarmalanmamış), koşullu tip number ve string'e ayrı ayrı uygulanır, bu da number[] ve string[] birleşimiyle sonuçlanır.
Koşullu Tiplerin Pratik Uygulamaları
- Extracting Return Types: Yukarıda gösterildiği gibi, bir fonksiyonun geri dönüş tipini çıkarma.
- Filtering Types from a Union: Bir union'dan yalnızca belirli tipleri içeren bir tip oluşturma.
- Defining Overloaded Function Types: Girdi tiplerine göre farklı fonksiyon tipleri oluşturma.
- Creating Type Guards: Bir değişkenin tipini daraltan fonksiyonlar tanımlama.
Uluslararası Örnek: Farklı Tarih Formatlarını Yönetme
Dünyanın farklı bölgeleri farklı tarih formatları kullanır. Bu farklılıkları yönetmek için koşullu tipleri kullanabilirsiniz.
type DateFormat = "YYYY-MM-DD" | "MM/DD/YYYY" | "DD.MM.YYYY";
type ParseDate = T extends "YYYY-MM-DD"
? { year: number; month: number; day: number; format: "YYYY-MM-DD" }
: T extends "MM/DD/YYYY"
? { month: number; day: number; year: number; format: "MM/DD/YYYY" }
: T extends "DD.MM.YYYY"
? { day: number; month: number; year: number; format: "DD.MM.YYYY" }
: never;
function parseDate(dateString: string, format: T): ParseDate {
// (Uygulama farklı tarih formatlarını işleyecektir)
if (format === "YYYY-MM-DD") {
const [year, month, day] = dateString.split("-").map(Number);
return { year, month, day, format } as ParseDate;
} else if (format === "MM/DD/YYYY") {
const [month, day, year] = dateString.split("/").map(Number);
return { month, day, year, format } as ParseDate;
} else if (format === "DD.MM.YYYY") {
const [day, month, year] = dateString.split(".").map(Number);
return { day, month, year, format } as ParseDate;
} else {
throw new Error("Geçersiz tarih formatı");
}
}
const parsedDateISO = parseDate("2023-10-27", "YYYY-MM-DD"); // Tip: { year: number; month: number; day: number; format: "YYYY-MM-DD"; }
const parsedDateUS = parseDate("10/27/2023", "MM/DD/YYYY"); // Tip: { month: number; day: number; year: number; format: "MM/DD/YYYY"; }
const parsedDateEU = parseDate("27.10.2023", "DD.MM.YYYY"); // Tip: { day: number; month: number; year: number; format: "DD.MM.YYYY"; }
console.log(parsedDateISO.year); // Orada olacağını bilerek yıla erişim
Bu örnek, belirtilen tarih formatına göre farklı tarih ayrıştırma fonksiyonları tanımlamak için koşullu tipleri kullanır. ParseDate tipi, döndürülen nesnenin formata göre doğru özelliklere sahip olmasını sağlar.
Şablon Dizi ve Koşullu Tipleri Birleştirme
Asıl güç, şablon dizi tipleri ve koşullu tipleri birleştirdiğinizde ortaya çıkar. Bu, inanılmaz derecede güçlü tip manipülasyonlarına olanak tanır.
type EventName = `on${Capitalize}`;
type ExtractEventPayload = T extends EventName
? { type: T; payload: any } // Gösterim için basitleştirilmiştir
: never;
type ClickEvent = EventName<"click">; // "onClick"
type MouseOverEvent = EventName<"mouseOver">; // "onMouseOver"
//Tip alan örnek fonksiyon
function processEvent(event: T): ExtractEventPayload {
//Gerçek bir uygulamada, olayı gerçekten gönderirdik.
console.log(`İşlenen olay ${event}`);
//Gerçek bir uygulamada, payload olay tipine bağlı olurdu.
return { type: event, payload: {} } as ExtractEventPayload;
}
//Dönüş tiplerinin çok spesifik olduğuna dikkat edin:
const clickEvent = processEvent("onClick"); // { type: "onClick"; payload: any; }
const mouseOverEvent = processEvent("onMouseOver"); // { type: "onMouseOver"; payload: any; }
//Başka dizeler kullanırsanız, never alırsınız:
// const someOtherEvent = processEvent("someOtherEvent"); // Tip `never` olur
En İyi Uygulamalar ve Dikkat Edilmesi Gerekenler
- Keep it Simple: Güçlü olsalar da, bu ileri seviye tipler hızla karmaşıklaşabilir. Anlaşılırlık ve sürdürülebilirlik için çaba gösterin.
- Test Thoroughly: Kapsamlı birim testleri yazarak tip tanımlarınızın beklendiği gibi davrandığından emin olun.
- Document Your Code: Kod okunabilirliğini artırmak için ileri seviye tiplerinizin amacını ve davranışını açıkça belgeleyin.
- Consider Performance: İleri seviye tiplerin aşırı kullanımı derleme süresini etkileyebilir. Kodunuzu profilleyin ve gerektiğinde optimize edin.
Sonuç
Şablon dizi tipleri ve koşullu tipler, TypeScript'in cephaneliğindeki güçlü araçlardır. Bu ileri seviye tiplerde uzmanlaşarak daha etkileyici, sürdürülebilir ve tip güvenli kod yazabilirsiniz. Bu özellikler, tipler arasındaki karmaşık ilişkileri yakalamanıza, daha katı kısıtlamalar uygulamanıza ve son derece yeniden kullanılabilir tip tanımları oluşturmanıza olanak tanır. TypeScript becerilerinizi yükseltmek ve küresel bir kitle için sağlam ve ölçeklenebilir uygulamalar oluşturmak için bu teknikleri benimseyin.